#include "kuaikan.h"

#include <gl/gl.h>
#include <gl/glu.h>


#include <kuai/misc/xyz.hpp>
#include <kuai/misc/debug.hpp>
#include <kuai/mol/ct.hpp>



using namespace kuai;

namespace kuai {
	inline void glVertex(const XYZ& v0) {
		glVertex3f(v0.x, v0.y, v0.z);
	}

	inline void glTranslate(const XYZ& delta) {
		glTranslatef(delta.x, delta.y, delta.z);
	}

	void glBall(const XYZ& center, const Byte color1[], RealNumber radius, Index slice, const XYZ& z, const XYZ& x) {

	}

	void glStick(
		const XYZ& center1, const Byte color1[], RealNumber radius1, 
		const XYZ& center2, const Byte color2[], RealNumber radius2, 
		Index slice, const XYZ& x) 
	{
		
	}

	void glCone(
		const XYZ& center1, const Byte color1[],
		const XYZ& center2, const Byte color2[], RealNumber radius2, 
		Index slice, const XYZ& x) 
	{
	
	}
}

KUAIKAN_API(void) setAxis(const XYZ axis[3]) {
	XYZ x(1, 0, 0);
	XYZ y(0, 1, 0);
	RealNumber angleX = angle(x, axis[0]);
	if (angleX > 0) {
		XYZ norm = x * axis[0];
		glRotatef(rad2deg(angleX), norm.x, norm.y, norm.z);
		y = rotate(y, norm, angleX);
	}
	RealNumber angleY = angle(y, axis[1]);
	if (angleY > 0) {
		glRotatef(rad2deg(angleY), axis[0].x, axis[0].y, axis[0].z);
	}
}

KUAIKAN_API(void) drawMol3DLine(
	Index buffer[],
	const XYZ coords[],
	const Byte colors[])
{
	ConnectTable ct(buffer);

	glBegin(GL_LINES);
	for (Index i = 0; i < ct.countBonds(); i++) {
		const Bond& bondI = ct.getBond(i);
		const Atom& atom1 = ct.getAtom(bondI, 0);
		const Atom& atom2 = ct.getAtom(bondI, 1);
		Index a1 = ct.indexOf(atom1);
		Index a2 = ct.indexOf(atom2);

		glColor3ub(colors[a1*3+0], colors[a1*3+1], colors[a1*3+2]);
		glVertex(coords[a1]);
		glColor3ub(colors[a2*3+0], colors[a2*3+1], colors[a2*3+2]);
		glVertex(coords[a2]);
	}
	glEnd();

	glBegin(GL_POINTS);
	for (Index i = 0; i < ct.countAtoms(); ++i) {
		if (ct.degree(ct.getAtom(i)) == 0) {
			glColor3ub(colors[i*3+0], colors[i*3+1], colors[i*3+2]);
			glVertex(coords[i]);
		}	
	}
	glEnd();
}


KUAIKAN_API(void) drawMol3DLine2(
	Index buffer[],
	const XYZ coords[],
	const Byte colors[])
{
	ConnectTable ct(buffer);

	glBegin(GL_LINES);
	for (Index i = 0; i < ct.countBonds(); i++) {
		const Bond& bondI = ct.getBond(i);
		const Atom& atom1 = ct.getAtom(bondI, 0);
		const Atom& atom2 = ct.getAtom(bondI, 1);
		Index a1 = ct.indexOf(atom1);
		Index a2 = ct.indexOf(atom2);

		XYZ mid((coords[a1]+coords[a2])/2);

		glColor3ub(colors[a1*3+0], colors[a1*3+1], colors[a1*3+2]);
		glVertex(coords[a1]);
		glVertex(mid);
		glColor3ub(colors[a2*3+0], colors[a2*3+1], colors[a2*3+2]);
		glVertex(mid);
		glVertex(coords[a2]);
	}
	glEnd();

	glBegin(GL_POINTS);
	for (Index i = 0; i < ct.countAtoms(); ++i) {
		if (ct.degree(ct.getAtom(i)) == 0) {
			glColor3ub(colors[i*3+0], colors[i*3+1], colors[i*3+2]);
			glVertex(coords[i]);
		}	
	}
	glEnd();
}


KUAIKAN_API(void) kuaikanAtomBalls(
	Index nAtoms,
	const XYZ coords[],
	const Byte colors[],
	const RealNumber radius[], 
	const Index atoms[], 
	const Index slice)
{
	GLUquadricObj* quadratic=gluNewQuadric();
	gluQuadricNormals(quadratic, GLU_SMOOTH);
	glPushMatrix();
	if (atoms == NULL) {
		XYZ last(0, 0, 0);
		for (Index i = 0; i < nAtoms; ++i) {
			glTranslate(coords[i] - last);
			glColor3ub(colors[i*3+0], colors[i*3+1], colors[i*3+2]);
			gluSphere(quadratic, radius[i], slice, slice);
			last = coords[i];
		}
	}
	else {
		XYZ last(0, 0, 0);
		for (Index i = 0; i < nAtoms; ++i) {
			glTranslate(coords[atoms[i]] - last);
			glColor3ub(colors[atoms[i]*3+0], colors[atoms[i]*3+1], colors[atoms[i]*3+2]);
			gluSphere(quadratic, radius[atoms[i]], slice, slice);
			last = coords[i];
		}
	}
	glPopMatrix();
	gluDeleteQuadric(quadratic);
}

KUAIKAN_API(void) kuaikanBondSticks(
	Index buffer[],
	const XYZ coords[],
	const Byte colors[],
	const Index slice)
{
	ConnectTable ct(buffer);
	GLUquadricObj* quadratic=gluNewQuadric();
	gluQuadricNormals(quadratic, GLU_SMOOTH);
	glPushMatrix();
	XYZ last(0, 0, 0);

	// TODO
	
	glPopMatrix();
	gluDeleteQuadric(quadratic);
}


KUAIKAN_API(void) rotateAxis(XYZ coords[3], RealNumber percentX, RealNumber percentY) {
	XYZ axis(-percentY, percentX, 0);
	axis /= abs(axis);
	RealNumber angle = PI * sqrt(percentX * percentX + percentY * percentY);
	coords[0] = rotate(coords[0], axis, angle);
	coords[1] = rotate(coords[1], axis, angle);
	coords[2] = rotate(coords[2], axis, angle);
}
